var isDecimal_re = /^\s*(\+|-)?((\d+([,\.]\d+)?)|([,\.]\d+))\s*$/
  , CSVParser = {
    isNumber: function(r) {
        return null != r && !isNaN(new Number(r))
    },
    parse: function(r, e, n, t, g, o) {
        var a = []
          , i = new RegExp("[^,]","gi")
          , l = r.replace(i, "").length;
        i = new RegExp("[^\t]","gi");
        var s = ",";
        r.replace(i, "").length > l && (s = "\t"),
        "comma" === n ? s = "," : "tab" === n && (s = "\t"),
        i = new RegExp("^\n+","gi"),
        r = r.replace(i, ""),
        i = new RegExp("\n+$","gi"),
        r = r.replace(i, "");
        for (var h = (a = this.CSVToArray(r, s)).length - 1; h >= 0; h--)
            for (var p = a[h].length - 1; p >= 0; p--)
                a[h][p] = a[h][p].replace("\t", "\\t"),
                a[h][p] = a[h][p].replace("\n", "\\n"),
                a[h][p] = a[h][p].replace("\r", "\\r");
        var f = []
          , u = []
          , c = a[0].length;
        a.length;
        if (e)
            f = a.splice(0, 1)[0],
            a.length;
        else
            for (h = 0; h < c; h++)
                f.push("val" + String(h)),
                u.push("");
        if (g)
            for (h = f.length - 1; h >= 0; h--)
                f[h] = f[h].toUpperCase();
        if (t)
            for (h = f.length - 1; h >= 0; h--)
                f[h] = f[h].toLowerCase();
        for (h = 0; h < a.length; h++) {
            a[h].length != c && this.log("Error parsing row " + String(h) + ". Wrong number of columns.")
        }
        var v = a.length;
        for (h = 0; h < f.length; h++) {
            for (var m = 0, L = 0, w = 0; w < v; w++)
                a[w] && (isDecimal_re.test(a[w][h]) && (a[w][h] = a[w][h].replace(",", ".")),
                CSVParser.isNumber(a[w][h]) && (L++,
                String(a[w][h]).indexOf(".") > 0 && m++));
            u[h] = L / v > .9 ? m > 0 ? "float" : "int" : "string"
        }
        return {
            dataGrid: a,
            headerNames: f,
            headerTypes: u,
            errors: this.getLog()
        }
    },
    errorLog: [],
    resetLog: function() {
        this.errorLog = []
    },
    log: function(r) {
        this.errorLog.push(r)
    },
    getLog: function() {
        var r = "";
        if (this.errorLog.length > 0) {
            for (var e = 0; e < this.errorLog.length; e++)
                r += "!!" + this.errorLog[e] + "!!\n";
            r += "\n"
        }
        return r
    },
    CSVToArray: function(r, e) {
        e = e || ",";
        for (var n = new RegExp("(\\" + e + '|\\r?\\n|\\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^"\\' + e + "\\r\\n]*))","gi"), t = [[]], g = null; g = n.exec(r); ) {
            var o = g[1];
            if (o.length && o != e && t.push([]),
            g[2])
                var a = g[2].replace(new RegExp('""',"g"), '"');
            else
                a = g[3];
            t[t.length - 1].push(a)
        }
        return t
    }
};
